package ch.sv7.tool.dbmanager.db.fixbuilder;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import ch.sv7.tool.dbmanager.Context;
import ch.sv7.tool.dbmanager.db.ColumnSchema;
import ch.sv7.tool.dbmanager.db.ForeignKeySchema;
import ch.sv7.tool.dbmanager.db.IndexSchema;
import ch.sv7.tool.dbmanager.db.SchemaElement;
import ch.sv7.tool.dbmanager.db.dialect.Dialect;
import ch.sv7.tool.dbmanager.db.dialect.DialectException;
import ch.sv7.tool.dbmanager.db.difference.AbstractColumnDifference;
import ch.sv7.tool.dbmanager.db.difference.ExtraColumnDifference;
import ch.sv7.tool.dbmanager.db.difference.SchemaDifference;
import ch.sv7.tool.dbmanager.db.fix.CreateForeignKeyFix;
import ch.sv7.tool.dbmanager.db.fix.CreateIndexFix;
import ch.sv7.tool.dbmanager.db.fix.DropForeignKeyFix;
import ch.sv7.tool.dbmanager.db.fix.DropIndexFix;
import ch.sv7.tool.dbmanager.db.fix.ImplicitUpdateColumnFix;
import ch.sv7.tool.dbmanager.db.fix.SchemaFix;
import ch.sv7.tool.dbmanager.types.TypeInfo;
import ch.sv7.tool.log.Logger;

/**
 * TODO: Document me!
 *
 * @author svt
 *
 */
public class ExtraColumnFixBuilder implements FilterFixBuilder {

	private static final Logger log = Logger.getLogger(ExtraColumnFixBuilder.class);

	private Set indexes = new HashSet();
	private Set foreignKeys = new HashSet();
	
	public SchemaFix[] createFixes(SchemaDifference difference, Dialect dialect, Context context) {
		ExtraColumnDifference extraColumnDifference= (ExtraColumnDifference)difference;
		boolean isTypeNullable = true;
		try {
			TypeInfo typeInfo = dialect.getTypesInfo().getTypeInfo(extraColumnDifference.getActualColumnSchema().getType().getTypeName());
			isTypeNullable = typeInfo.isNullable();
		} catch (DialectException e) {
			log.error(e.getMessage());
		}
		if (!extraColumnDifference.getActualColumnSchema().getType().isNullable() && isTypeNullable){
			List fixes = new ArrayList();
			/*
			 * Clone to prevent side-effect changes to DatabaseSchema
			 */
			ColumnSchema columnToDisable = extraColumnDifference.getActualColumnSchema().cloneColumn();
			columnToDisable.getType().setNullable(true);

			/*
			 * Drop indexes if needed
			 */
			Iterator oldIndexIter = getIndexesToDrop(extraColumnDifference);
			while (oldIndexIter.hasNext()) {
				IndexSchema index = (IndexSchema)oldIndexIter.next();
				indexes.add(((SchemaElement)index).getSchemaIdentifier());
				fixes.add(new DropIndexFix(index));
			}		
			Iterator newIndexIter = getIndexesToCreate(extraColumnDifference);
			while (newIndexIter.hasNext()) {
				IndexSchema index = (IndexSchema)newIndexIter.next();
				indexes.add(((SchemaElement)index).getSchemaIdentifier());
				fixes.add(new CreateIndexFix(index));
			}	
			Iterator oldFkIter = getForeignKeyToDrop(extraColumnDifference);
			while (oldFkIter.hasNext()) {
				ForeignKeySchema fk = (ForeignKeySchema)oldFkIter.next();
				foreignKeys.add(((SchemaElement)fk).getSchemaIdentifier());
				fixes.add(new DropForeignKeyFix(fk));
			}		
			Iterator newFkIter = getForeignKeyToCreate(extraColumnDifference);
			while (newFkIter.hasNext()) {
				ForeignKeySchema fk = (ForeignKeySchema)newFkIter.next();
				foreignKeys.add(((SchemaElement)fk).getSchemaIdentifier());
				fixes.add(new CreateForeignKeyFix(fk));
			}	
			ImplicitUpdateColumnFix fix = new ImplicitUpdateColumnFix(columnToDisable);
			fix.setIgnoreDefault(true);
			fixes.add(fix);
			return (SchemaFix[])fixes.toArray(new SchemaFix[fixes.size()]);
		} else {
			/*
			 * Do nothing if column is nullable
			 */
			return new SchemaFix[]{};
		}
	}

	public Iterator getIndexesToDrop(AbstractColumnDifference columnDifference) {
		return new ArrayList().iterator();
	}
		
	public Iterator getIndexesToCreate(AbstractColumnDifference columnDifference) {
		return new ArrayList().iterator();
	}
		
	public Iterator getForeignKeyToDrop(AbstractColumnDifference columnDifference) {
		return new ArrayList().iterator();
	}	
	
	public Iterator getForeignKeyToCreate(AbstractColumnDifference columnDifference) {
		return new ArrayList().iterator();
	}	
	
	
	public boolean ignoreFix(SchemaFix fix) {
		String identifier = fix.getActionTarget().getSchemaIdentifier();
		/*
		 * Remove all editions on index that will be dropped
		 */
		if (indexes.contains(identifier) && fix.getAction() == SchemaFix.ACTION_EDIT){
			return true;
		}	
		/*
		 * Remove all editions on foreign keys that will be dropped
		 */
		if (foreignKeys.contains(identifier) && fix.getAction() == SchemaFix.ACTION_EDIT){
			return true;
		}	
		
		return false;
	}
}
